| 1 |
'use client'; |
| 2 |
|
| 3 |
import { useState, useEffect } from 'react'; |
| 4 |
import Link from 'next/link'; |
| 5 |
import { useParams } from 'next/navigation'; |
| 6 |
import { getConflicts, getPeopleByConflict, Conflict, Person } from '@/lib/api'; |
| 7 |
import Header from '@/components/Header'; |
| 8 |
|
| 9 |
export default function ConflictPage() { |
| 10 |
const params = useParams(); |
| 11 |
const conflictId = parseInt(params.id as string); |
| 12 |
|
| 13 |
const [conflict, setConflict] = useState<Conflict | null>(null); |
| 14 |
const [people, setPeople] = useState<Person[]>([]); |
| 15 |
const [loading, setLoading] = useState(true); |
| 16 |
const [error, setError] = useState<string | null>(null); |
| 17 |
|
| 18 |
useEffect(() => { |
| 19 |
async function fetchData() { |
| 20 |
try { |
| 21 |
const conflicts = await getConflicts(); |
| 22 |
const currentConflict = conflicts.find(c => c.id === conflictId); |
| 23 |
|
| 24 |
if (!currentConflict) { |
| 25 |
throw new Error('Conflict not found'); |
| 26 |
} |
| 27 |
|
| 28 |
setConflict(currentConflict); |
| 29 |
const peopleData = await getPeopleByConflict(conflictId); |
| 30 |
setPeople(peopleData); |
| 31 |
} catch (err) { |
| 32 |
setError(err instanceof Error ? err.message : 'Failed to load data'); |
| 33 |
console.error(err); |
| 34 |
} finally { |
| 35 |
setLoading(false); |
| 36 |
} |
| 37 |
} |
| 38 |
|
| 39 |
fetchData(); |
| 40 |
}, [conflictId]); |
| 41 |
|
| 42 |
if (loading) { |
| 43 |
return ( |
| 44 |
<div className="min-h-screen bg-vmi-cream flex items-center justify-center"> |
| 45 |
<p className="text-gray-600 text-xl">Loading...</p> |
| 46 |
</div> |
| 47 |
); |
| 48 |
} |
| 49 |
|
| 50 |
if (error || !conflict) { |
| 51 |
return ( |
| 52 |
<div className="min-h-screen bg-vmi-cream flex items-center justify-center"> |
| 53 |
<div className="text-center"> |
| 54 |
<p className="text-red-600 mb-4 text-xl">{error || 'Conflict not found'}</p> |
| 55 |
<Link href="/" className="text-vmi-red hover:text-vmi-dark-red underline font-semibold"> |
| 56 |
Return to Home |
| 57 |
</Link> |
| 58 |
</div> |
| 59 |
</div> |
| 60 |
); |
| 61 |
} |
| 62 |
|
| 63 |
return ( |
| 64 |
<div className="min-h-screen bg-vmi-cream"> |
| 65 |
<Header |
| 66 |
breadcrumbs={[ |
| 67 |
{ label: 'Home', href: '/' }, |
| 68 |
{ label: conflict.name } |
| 69 |
]} |
| 70 |
/> |
| 71 |
|
| 72 |
{/* Main Content */} |
| 73 |
<main className="max-w-6xl mx-auto px-4 py-12"> |
| 74 |
{/* Conflict Header */} |
| 75 |
<div className="bg-vmi-light-gold border-2 border-vmi-gold rounded-lg p-8 mb-12 shadow-xl"> |
| 76 |
<h1 className="text-4xl font-black text-vmi-red mb-4"> |
| 77 |
{conflict.name} |
| 78 |
</h1> |
| 79 |
<p className="text-xl text-gray-700 mb-4"> |
| 80 |
{conflict.start_year} – {conflict.end_year || 'Present'} |
| 81 |
</p> |
| 82 |
{conflict.description && ( |
| 83 |
<p className="text-gray-800 leading-relaxed mb-6">{conflict.description}</p> |
| 84 |
)} |
| 85 |
<div className="border-t-2 border-vmi-gold pt-6"> |
| 86 |
<p className="text-2xl font-bold text-vmi-red"> |
| 87 |
{conflict.casualty_count} VMI Alumni Gave Their Lives |
| 88 |
</p> |
| 89 |
</div> |
| 90 |
</div> |
| 91 |
|
| 92 |
{/* People List */} |
| 93 |
<div className="bg-white border-2 border-gray-300 rounded-lg p-8 shadow-xl"> |
| 94 |
<h2 className="text-3xl font-bold mb-8 text-center text-vmi-red"> |
| 95 |
Honor Roll |
| 96 |
</h2> |
| 97 |
|
| 98 |
{people.length === 0 ? ( |
| 99 |
<p className="text-center text-gray-600 text-lg">No casualties recorded yet.</p> |
| 100 |
) : ( |
| 101 |
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> |
| 102 |
{people.map((person) => ( |
| 103 |
<Link |
| 104 |
key={person.id} |
| 105 |
href={`/memorial/person/${person.id}`} |
| 106 |
className="block p-6 border-2 border-gray-200 rounded-lg hover:border-vmi-gold hover:bg-vmi-light-gold transition-all duration-200 group" |
| 107 |
> |
| 108 |
<h3 className="text-xl font-bold text-gray-800 group-hover:text-vmi-red transition-colors mb-2"> |
| 109 |
{person.full_display_name || person.display_name} |
| 110 |
</h3> |
| 111 |
{person.rank && ( |
| 112 |
<p className="text-gray-700 font-semibold">{person.rank}</p> |
| 113 |
)} |
| 114 |
{person.unit && ( |
| 115 |
<p className="text-gray-600 text-sm italic">{person.unit}</p> |
| 116 |
)} |
| 117 |
</Link> |
| 118 |
))} |
| 119 |
</div> |
| 120 |
)} |
| 121 |
</div> |
| 122 |
</main> |
| 123 |
</div> |
| 124 |
); |
| 125 |
} |